package xfuzzy.alg_genetico.modelo;

import xfuzzy.alg_genetico.doble_cromosoma.codification.Encoder;
import xfuzzy.alg_genetico.doble_cromosoma.codification.DoubleChromosome;
import xfuzzy.alg_genetico.doble_cromosoma.finalversion.XfghlConfig;
import xfuzzy.alg_genetico.doble_cromosoma.output.ConfigurationHandler;
import xfuzzy.lang.Specification;
import xfuzzy.lang.XflException;
import xfuzzy.xfhl.model.XfhlData;
import xfuzzy.xfhl.model.hierStruct.XfhlHierStruct;
import xfuzzy.xfhl.model.hierStruct.XfhlModule;
import xfuzzy.xfhl.model.hierStruct.XfhlSingleHierStruct;
import xfuzzy.xfsl.model.XfslAlgorithm;
import xfuzzy.xfsl.model.XfslAlgorithmFactory;
import xfuzzy.xfsl.model.XfslConfig;
import xfuzzy.xfsl.model.XfslEndCondition;
import xfuzzy.xfsl.model.XfslErrorFunction;
import xfuzzy.xfsl.model.XfslThread;
import xfuzzy.xfsl.model.algorithm.Marquardt;
import xfuzzy.xfsl.model.algorithm.RProp;
import xfuzzy.xfsl.model.algorithm.XfslGradientBasedAlgorithm;

/*
 * Esta clase ejecuta el mismo codigo que la clase XfhlThread, pero de forma
 * no paralela
 * */

public class MyXfhlThread2 {

	/**
	 * Identificador de la hebra
	 */
	private int idThread;

	/**
	 * Configuracion del modulo Xfhl
	 */
	private XfghlConfig conxfgfhl;

	/**
	 * Instancia del xfhlData que va a utilizar la hebra
	 */
	private XfhlData data;
	
	//private MyXfhlView window;

	/**
	 * Constructor
	 * 
	 * @param idThread
	 *            Identificador de la Hebra
	 * @param conf
	 *            Configuracion de la herramienta XfhlConfig
	 * @param data
	 *            XfhlData que utilizara la hebra
	 */
	public MyXfhlThread2(int idThread, XfghlConfig conf, XfhlData data) {
		this.idThread = idThread;
		this.conxfgfhl = conf;
		this.data = data;
		//this.window = new MyXfhlView();
	}
	
	public MyXfhlThread2(int idThread, XfghlConfig conf) {
		this.idThread = idThread;
		this.conxfgfhl = conf;
		//this.window = new MyXfhlView();
	}
	

	/**
	 * Ejecucion de la hebra
	 */
	public void ejecucion2(XfhlHierStruct struc2) {

		// Obtenemos una instancia del singlenton
		XfhlSingleHierStruct singleHier = XfhlSingleHierStruct.getInstance();
		if (singleHier != null) {
			// Declaramos una estructura jerarquica
			XfhlHierStruct struc;
			int counter = 1;

			// Mientras que haya estructuras
			while ((struc = singleHier.getXfhlHierStruct()) != null) {
			
				// Creamos la especificacion
				Specification spec = null;

				try {

					spec = MyXfhlSpecification.create(struc2, this.conxfgfhl);
				} 
				catch (XflException e) {
					e.printStackTrace();
				}
				XfhlModule modulo1 = (XfhlModule) struc.getModulo();
				//System.out.println(this.confXfhl.getnumVarEnt());
				DoubleChromosome cromosoma = Encoder.codeBackwardAnchura(modulo1, conxfgfhl.getnumVarEnt());
				//window.updateBestSpec(spec);
				//System.out.println();
				// Ajustamos la especificacion
				this.data.setSpec(spec);
				learning(spec);
				//String output = codificacion.getCodificacion();
				String output = Encoder.generarCanonico(cromosoma);
				output += " : " + this.data.getFinalError();
//				if (conxfgfhl.getnumVarEnt() == 6)  {
//					if (conxfgfhl.getnumIterAjust() == 1)
//						ConfigurationHandler.writeConfiguration(output, "configuration_6_anchura_canonico_ite1.txt");
//					if (conxfgfhl.getnumIterAjust() == 40)
//						ConfigurationHandler.writeConfiguration(output, "configuration_6_anchura_canonico_ite40.txt");
//				}
//				if (conxfgfhl.getnumVarEnt() == 7)  {
//					if (conxfgfhl.getnumIterAjust() == 1)
//						ConfigurationHandler.writeConfiguration(output, "configuration_7_anchura_canonico_ite1.txt");
//					if (conxfgfhl.getnumIterAjust() == 40)
//						ConfigurationHandler.writeConfiguration(output, "configuration_7_anchura_canonico_ite40.txt");
//				}
				System.out.println(counter + ":" + output);
				counter++;
			}
		}
		System.out.println("Soy la hebra " + this.idThread + " y he terminado.");
		//this.window.dispose();
	}
	
	public void ejecucion3(XfhlHierStruct struc2, XfhlData dataNew) {

		// Obtenemos una instancia del singlenton
		XfhlSingleHierStruct singleHier = XfhlSingleHierStruct.getInstance();
		if (singleHier != null) {
			// Declaramos una estructura jerarquica
			XfhlHierStruct struc;
			int counter = 1;

			// Mientras que haya estructuras
			while ((struc = singleHier.getXfhlHierStruct()) != null) {
			
				// Creamos la especificacion
				Specification spec = null;

				try {

					spec = MyXfhlSpecification.create(struc2, this.conxfgfhl);
				} 
				catch (XflException e) {
					e.printStackTrace();
				}
				XfhlModule modulo1 = (XfhlModule) struc.getModulo();
				//System.out.println(this.confXfhl.getnumVarEnt());
				DoubleChromosome cromosoma = Encoder.codeBackwardAnchura(modulo1, conxfgfhl.getnumVarEnt());
				//window.updateBestSpec(spec);
				//System.out.println();
				// Ajustamos la especificacion
				//this.data.setSpec(spec);
				dataNew.setSpec(spec);
				learning3(spec, dataNew);
				//String output = codificacion.getCodificacion();
				String output = Encoder.generarCanonico(cromosoma);
				output += " : " + dataNew.getFinalError();
//				if (conxfgfhl.getnumVarEnt() == 6)  {
//					if (conxfgfhl.getnumIterAjust() == 1)
//						ConfigurationHandler.writeConfiguration(output, "configuration_6_anchura_canonico_ite1.txt");
//					if (conxfgfhl.getnumIterAjust() == 40)
//						ConfigurationHandler.writeConfiguration(output, "configuration_6_anchura_canonico_ite40.txt");
//				}
//				if (conxfgfhl.getnumVarEnt() == 7)  {
//					if (conxfgfhl.getnumIterAjust() == 1)
//						ConfigurationHandler.writeConfiguration(output, "configuration_7_anchura_canonico_ite1.txt");
//					if (conxfgfhl.getnumIterAjust() == 40)
//						ConfigurationHandler.writeConfiguration(output, "configuration_7_anchura_canonico_ite40.txt");
//				}
				System.out.println(counter + ":" + output);
				counter++;
			}
		}
		System.out.println("Soy la hebra " + this.idThread + " y he terminado.");
		//this.window.dispose();
	}

	/**
	 * Ajusta las salidas del sistema con el algoritmo aprendizaje
	 */
	private void learning(Specification spec) {

		XfslThread lrnthread = new XfslThread(spec, createtXfslConfig());

		// Añadimos al objeto data como observador para notificarle los cambios
		//lrnthread.addObserver(this.data);

		try {
			lrnthread.tuning();
		} 
		catch (XflException e) {
			e.printStackTrace();
		}
	}
	
	private void learning3(Specification spec, XfhlData dataNew) {

		XfslThread lrnthread = new XfslThread(spec, createtXfslConfig());

		// Añadimos al objeto data como observador para notificarle los cambios
		lrnthread.addObserver(dataNew);

		try {
			lrnthread.tuning();
		} 
		catch (XflException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Crea una configuracion para la herramienta de ajuste con la configuracion
	 * de la herramienta Xfhl
	 * 
	 * @return La configuracion de la herramienta Xfsl
	 */
	public XfslConfig createtXfslConfig() {
		
		XfslConfig xfslConfig = new XfslConfig();

		// Parametros del algoritmo
		double param[] = { this.conxfgfhl.getIniUpd(), this.conxfgfhl.getIncFact(), this.conxfgfhl.getDecFact() };

		int alg = -1;
		int err = XfslErrorFunction.MEAN_SQUARE_ERROR;
		int end = XfslEndCondition.EPOCH;

		if (this.conxfgfhl.getAlgorithm() == 0) {
			alg = XfslAlgorithm.RPROP;

			RProp rprop;
			try {
				rprop = (RProp) XfslAlgorithmFactory.createAlgorithm(alg, param);
				// rprop.setOption(RProp.COMPUTE,
				// this.confXfhl.getPerturbation());
				rprop.setOption(RProp.COMPUTE,
						XfslGradientBasedAlgorithm.COMPUTE);
				xfslConfig = new XfslConfig();
				xfslConfig.trainingfile = this.conxfgfhl.getDataSetFile();
				xfslConfig.algorithm = rprop;
				xfslConfig.errorfunction = new XfslErrorFunction(err);
				xfslConfig.endcondition.setLimit(end, this.conxfgfhl.getnumIterAjust());

			} 
			catch (XflException e) {
				e.printStackTrace();
			}
		} else if (this.conxfgfhl.getAlgorithm() == 1) {

			alg = XfslAlgorithm.MARQUARDT;
			Marquardt marq;
			try {
				marq = (Marquardt) XfslAlgorithmFactory.createAlgorithm(alg, param);
				// marq.setOption(Marquardt.COMPUTE,
				// this.confXfhl.getPerturbation());
				marq.setOption(Marquardt.COMPUTE, 0);
				xfslConfig = new XfslConfig();
				xfslConfig.trainingfile = this.conxfgfhl.getDataSetFile();
				xfslConfig.algorithm = marq;
				xfslConfig.errorfunction = new XfslErrorFunction(err);
				xfslConfig.endcondition.setLimit(end,
						this.conxfgfhl.getnumIterAjust());

			} 
			catch (XflException e) {
				e.printStackTrace();
			}
		}

		return xfslConfig;
	}

	/**
	 * GETTERS AND SETTERS
	 * */
	public XfhlData getData() {
		return this.data;
	}
}